package com.xinghen.scheduler.client;

import com.xinghen.core.RestResponse;
import com.xinghen.rms.Rms;
import com.xinghen.scheduler.client.domain.RmsJobParam;
import com.xinghen.scheduler.client.domain.RmsJobResult;
import com.xinghen.scheduler.client.executor.AbstractExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author xinghen
 * @ClassName: SchClientHandle
 * @Package: com.xinghen.scheduler.client
 * @Description SchClientService
 * @create 2017-12-08 17:00
 */
@Component
@Slf4j
public class SchClientHandle implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Autowired
    private Rms rms;

    /**
     * 异步执行
     *
     * @param param
     * @param result
     */
    @Async
    public void asyncHandle(RmsJobParam param, RmsJobResult result) {
        try {
            //执行
            this.handle(param);
            result.setClientEndExecuteTime(new Date());
            result.setStats(RmsJobStats.COMPLETE.value());
            //回调
            this.callback(result);
        } catch (Exception e) {
            result.setClientEndExecuteTime(new Date());
            result.setStats(RmsJobStats.ERROR.value());
            result.setErrorMsg(ExceptionUtils.getStackTrace(e));
            //回调
            this.callback(result);
            //抛出异常
            log.error("asyncHandle error:", e);
            throw new SchException(e);
        }
    }

    /**
     * 同步执行
     *
     * @param param
     */
    public void handle(RmsJobParam param) {
        //判断bean是否存在
        if (!applicationContext.containsBean(param.getBeanName())) {
            throw new SchException(param.getBeanName() + " not defined");
        }
        //获得bean
        AbstractExecutor bean = applicationContext.getBean(param.getBeanName(), AbstractExecutor.class);
        //执行
        bean.handle(param);
    }

    /**
     * 回调(重处理)
     *
     * @param result
     */
    @Retryable(value = Exception.class)
    private void callback(RmsJobResult result) {
        log.info("try to callback");
        final String serviceCode = "SCH_CLIENT_CALLBACK_1";
        rms.call(serviceCode, result, null, new ParameterizedTypeReference<RestResponse<String>>() {
        }, null);
    }

    /**
     * 重试失败后执行的方法
     *
     * @param e
     */
    @Recover
    public void recover(Exception e) {
        log.error("try to callback failed:", e);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
